﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MSMQTriggerObjects;
using System.Collections;

namespace MSMQ.Triggers
{
	/// <summary>
	/// Collection of <see cref="TriggerInfo"/> objects available on a specified machine.
	/// </summary>
	public class TriggerSet
		: IEnumerable<Trigger>
	{
		#region Data Members

		/// <summary>
		/// Internal MSMQ trigger set object from the MSMQTriggerObjects library.
		/// </summary>
		private MSMQTriggerSet _internalTriggerSet;

		/// <summary>
		/// The active machine the trigger set is operating on.
		/// </summary>
		private string _machineName;

		/// <summary>
		/// List of triggers.
		/// </summary>
		private List<Trigger> _triggers;

		#endregion

		#region Constructor(s)

		/// <summary>
		/// Creates a <see cref="TriggerSet"/> loaded with the current machine's triggers.
		/// </summary>
		public TriggerSet()
			: this(Environment.MachineName)
		{
		}

		/// <summary>
		/// Creates a <see cref="TriggerSet"/> loaded with the specified machine's triggers.
		/// </summary>
		/// <param name="machineName">The name of the machine to get the triggers of.</param>
		public TriggerSet(string machineName)
		{
			_machineName = machineName;
			_internalTriggerSet = new MSMQTriggerSetClass();
			_internalTriggerSet.Init(_machineName);
			_internalTriggerSet.Refresh();
			LoadAll();
		}

		#endregion

		#region Support Methods

		/// <summary>
		/// Gets all the triggers available on the given machine.
		/// </summary>
		private void LoadAll()
		{
			_triggers = new List<Trigger>();
			for (int index = 0; index < _internalTriggerSet.Count; index++)
			{
				_triggers.Add(Load(index));
			}
		}

		/// <summary>
		/// Gets the trigger at the specified index in MSMQ.
		/// </summary>
		/// <param name="index">The index of the trigger to get.</param>
		/// <returns>A <see cref="TriggerInfo"/> containing information on the trigger.</returns>
		private Trigger Load(int index)
		{
			_internalTriggerSet.Refresh();
			string triggerId = null;
			string triggerName = null;
			string queueName = null;
			SystemQueueIdentifier sysQueueId = SystemQueueIdentifier.SYSTEM_QUEUE_NONE;
			int ruleCount = 0;
			int isEnabled = 0;
			int isSerialized = 0;
			MsgProcessingType msgProcType = MsgProcessingType.PEEK_MESSAGE;
			_internalTriggerSet.GetTriggerDetailsByIndex(index, out triggerId, out triggerName, out queueName, out sysQueueId, out ruleCount, out isEnabled, out isSerialized, out msgProcType);

			Trigger triggerInfo = new Trigger();
			triggerInfo.Id = triggerId;
			triggerInfo.Name = triggerName;
			triggerInfo.QueueName = queueName;
			triggerInfo.SystemQueueIdentifier = sysQueueId;
			triggerInfo.RuleCount = ruleCount;
			triggerInfo.IsEnabled = isEnabled == 1 ? true : false;
			triggerInfo.IsSerialized = isSerialized == 1 ? true : false;
			triggerInfo.MessageProcessingType = msgProcType;
			return triggerInfo;
		}

		/// <summary>
		/// Update's the specified trigger.
		/// </summary>
		/// <param name="triggerInfo">The trigger to update.</param>
		public void Update(Trigger triggerInfo)
		{
			_internalTriggerSet.Refresh();
			_internalTriggerSet.UpdateTrigger(
				triggerInfo.Id,
				triggerInfo.Name,
				triggerInfo.QueueName,
				triggerInfo.SystemQueueIdentifier,
				triggerInfo.IsEnabled ? 1 : 0,
				triggerInfo.IsSerialized ? 1 : 0,
				triggerInfo.MessageProcessingType);
		}

		#endregion

		#region IEnumerable<TriggerInfo> Members

		/// <summary>
		/// Gets the enumerator.
		/// </summary>
		/// <returns>An <see cref="IEnumerator"/>.</returns>
		public IEnumerator<Trigger> GetEnumerator()
		{
			return _triggers.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		/// <summary>
		/// Gets the enumerator.
		/// </summary>
		/// <returns>An <see cref="IEnumerator"/>.</returns>
		IEnumerator IEnumerable.GetEnumerator()
		{
			return _triggers.GetEnumerator() as IEnumerator;
		}

		#endregion
	}
}